using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Text;

namespace CoreCalc.SheetDefinedFunctions
{
  public abstract class Variable : IEquatable<Variable>
  {
    private readonly string name;
    private readonly Typ type;

    public Variable(String name, Typ type)
    {
      this.name = name;
      this.type = type;
    }

    public bool Equals(Variable that)
    {
      return this == that;
    }

    public override bool Equals(Object obj)
    {
      return Equals(obj as Variable);
    }

    public override int GetHashCode()
    {
      return base.GetHashCode();
    }

    public abstract void EmitLoad(ILGenerator ilg);

    public abstract void EmitStore(ILGenerator ilg);

    public String Name
    {
      get { return name; }
    }

    public Typ Type
    {
      get { return type; }
    }
  }

  public class LocalVariable : Variable
  {
    private readonly LocalBuilder var;

    public LocalVariable(ILGenerator ilg, String name, Typ type)
      : base(name, type)
    {
      if (type == Typ.Number)
        this.var = ilg.DeclareLocal(typeof(double));
      else
        this.var = ilg.DeclareLocal(Value.type);
    }

    public override void EmitLoad(ILGenerator ilg)
    {
      ilg.Emit(OpCodes.Ldloc, var);
    }

    public override void EmitStore(ILGenerator ilg)
    {
      ilg.Emit(OpCodes.Stloc, var);
    }
  }

  public class LocalArgument : Variable
  {
    private readonly int argumentNumber;

    public LocalArgument(String name, Typ type, int argumentNumber)
      : base(name, type)
    {
      this.argumentNumber = argumentNumber;
    }

    public override void EmitLoad(ILGenerator ilg)
    {
      ilg.Emit(OpCodes.Ldarg, argumentNumber);
    }

    public override void EmitStore(ILGenerator ilg)
    {
      throw new ImpossibleException("LocalArgument.EmitStore unexpected");
    }
  }
}
